
//模块初始化头文件
#include <linux/module.h>
//文件系统头文件　  filesystem
#include <linux/fs.h>
#include <mach/gpio.h>
//字符设备头文件  character device
#include <linux/cdev.h>
#include "7102_led.h"
#include <asm/uaccess.h>

#include <linux/device.h>




#define   led_major  0
#define   led_mijor  3
#define   led_jorcmt 5
static dev_t leddev_major;

#define LED_NAME  "gk7102_led"
char itk_buf[100] = {0};
//static struct cdev  itkdevice ; //用全局变量，不用分配空间
static struct cdev  *itk_pdev; //指针需要申请内存
static struct class *itkled_cls;
#define ITKCLASS    "itkclass"
#define itkdevname  "itkled"
static struct device *itkdev = NULL;


extern void gk_gpio_set_out(u32 pin, u32 value);


//int (*open) (struct inode *, struct file *);
int itkled_open(struct inode *itkinode, struct file *itkfile)
{
	printk(KERN_INFO "itk open\n");

	return 0;
}

//ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t itkled_read(struct file *itkfile, char __user *itkuser, size_t itklen, loff_t *itkloff)
{
    unsigned long ret = 0;
    
	printk(KERN_INFO "itk read\n");
    ret = copy_to_user(itkuser, itk_buf, itklen);
    if(ret !=0)
    {
        printk(KERN_ERR "cope to user faile\n");
        return -2;
    }
    printk("user read:%s",itkuser);

	return 0;
}
//ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t itkled_write(struct file *itkfile, const char __user *itkuser, size_t itklen, loff_t *itkloff)
{
    unsigned long ret = 0;
    
	printk(KERN_INFO "itk write\n");
    memset(itk_buf, 0, sizeof(itk_buf));
    ret = copy_from_user(itk_buf,itkuser,itklen);
    if(ret != 0)
    {
        printk(KERN_ERR "copy from user  faile\n");
        return -1;
    }
    printk(KERN_INFO "write len is %d\n",itklen);
    printk(KERN_INFO "user write string is %s\n",itk_buf);

	return 0;
}

//long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long itkled_ioctl(struct file *itkfile, unsigned int itkcmd, unsigned long itkarg)
{
    int gpio_val = -1;
    
    printk(KERN_INFO "you input cmd is = %d\n",itkcmd);

    switch(itkcmd)
    {
        case itkled_on:
            gk_gpio_set_out(15, 1);
            break;
        case itkled_off:
            gk_gpio_set_out(15, 0);
            break;
        case itkread_led:
            gpio_val = gk_gpio_get(15);
            if(gpio_val == 1)
                printk("LED is on\n");
            else
                printk("LED is off\n");
            break;
        default:
            printk("I do not you cmd");
            break;
    }
    
	return 0;
}
//int (*release) (struct inode *, struct file *);
int itkled_close(struct inode *itkinode, struct file *itkfile)
{
	printk(KERN_INFO "itk close\n");

	return 0;
}

static  struct file_operations  gk7102led_fops = {
    .owner      = THIS_MODULE, ////指的是该操作属于当前的模块

	.open			= itkled_open,
	.read			= itkled_read,
	.write			= itkled_write,
	.unlocked_ioctl = itkled_ioctl,
	.release		= itkled_close,
};


//申请
static int __init gk7102_led_init(void)
{
    int ret = 0;
#if 0
    led_major = register_chrdev(0, LED_NAME, &gk7102led_fops);
    if(led_major < 0)
    {
        printk(KERN_ERR "7102_led register_chrdev err \n");
        return -1;
    }
    printk(KERN_INFO "register_chrdev ok major = %d\n",led_major);
#endif

    //新的注册接口，两步走
    if(led_major)
    {
        leddev_major = MKDEV(led_major, led_mijor); //指定主设备号

        //1>注册第一张HASH表
        ret = register_chrdev_region(leddev_major, led_jorcmt, LED_NAME);
        if(ret != 0)
        {
            printk(KERN_INFO "register_chrdev_region err \n");
            goto out;
        }
    }
    else
    {
        ret = alloc_chrdev_region(&leddev_major, led_mijor, led_jorcmt, LED_NAME);
        if(ret != 0)
        {
            printk(KERN_INFO "alloc_chrdev_region err \n");
            goto out;
        }
        printk(KERN_INFO "led_major = %d\n",MAJOR(leddev_major));
    }
    
    //2>注册第二张HASH表
    //cdev_init(&itkdevice, &gk7102led_fops); //不用申请内存，直接初始化
    itk_pdev = cdev_alloc();
    if(NULL == itk_pdev)
    {
        printk(KERN_ERR "alloc err\n");
        goto out1;
    }
    itk_pdev->ops = &gk7102led_fops;
    ret = cdev_add(itk_pdev, leddev_major, led_jorcmt);
    if(ret != 0)
    {
        printk(KERN_ERR "cdev_add err\n");
        goto out2;
    }

    printk("register ok\n");

    //注册完成后
    //1、创建设备类
    itkled_cls = class_create(THIS_MODULE, ITKCLASS);
    if(IS_ERR(itkled_cls))
    {
        ret = PTR_ERR(itkled_cls);
        printk(KERN_ERR "create class fail \n");
        goto out3;
    }
    //2、创建设备设备与字符设备关联
    itkdev = device_create(itkled_cls, NULL, leddev_major, NULL, itkdevname"-%d", 77);
    if(IS_ERR(itkdev))
    {
        ret = PTR_ERR(itkdev);
        printk(KERN_ERR "device create fail\n");
        goto out4;
    }
    printk(KERN_INFO "device create success\n");
    
	//申请成功后亮灯
	//gk_gpio_set_out(15, 1);

    return 0;

out4:
    class_destroy(itkled_cls);
out3:
out2:
    cdev_del(itk_pdev);
out1:
    unregister_chrdev_region(leddev_major, led_jorcmt);
out:
    return ret;
}

static void __exit gk7102_led_exit(void)
{
    //unregister_chrdev(led_major, LED_NAME);
    //printk(KERN_INFO "rmmod ok\n");

    //1、删除设备
    device_del(itkdev);
    //2、删除设备类
    class_destroy(itkled_cls);
    
    cdev_del(itk_pdev);
    unregister_chrdev_region(leddev_major, led_jorcmt);
	//释放后灭灯
	//gk_gpio_set_out(15,0);
}

module_init(gk7102_led_init);
module_exit(gk7102_led_exit);


MODULE_LICENSE("GPL");


